package com.example.lockLearning;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Condition2<T> {

    // 队列
    private final Queue<T> queue = new LinkedList<>();
    // 容量
    private final int capacity;
    // 锁
    private final Lock lock = new ReentrantLock();
    /**
     * 生产者：放入产品
     * 生产队列
     */
    private final Condition notFull = lock.newCondition();
    /**
     * 消费者：拿出产品
     * 消费队列
     */
    private final Condition notEmpty = lock.newCondition();

    public Condition2(int capacity) {
        this.capacity = capacity;
    }

    /**
     * 放入产品
     *
     * @param item
     */
    public void put(T item) throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == capacity) {
                System.out.println("队列满，生产者等待。。。");
                /**
                 * 生产空间已满，需要等待生产空间空余
                 */
                notFull.await();
            }
            queue.offer(item);
            System.out.println("生产：" + item);
            /**
             * 激活消费线程
             */
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 取出产品
     *
     * @return
     */
    public T take() throws InterruptedException {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                System.out.println("队列空，消费者等待。。。");
                /**
                 * 生产空间已空，需要等待生产空间留余
                 */
                notEmpty.await();
            }
            T item = queue.poll();
            System.out.println("消费：" + item);
            /**
             * 激活生产者线程
             */
            notFull.signal();
            return item;
        } finally {
            lock.unlock();
        }
    }

}

class Condition2Test {
    public static void main(String[] args) {
        Condition2<Integer> condition2 = new Condition2<>(3);

        /**
         * 生产者线程
         */
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    condition2.put(i);
                    Thread.sleep(300);
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();

        /**
         * 消费者线程
         */
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    condition2.take();
                    Thread.sleep(600);
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();

    }
}
